<?php
/**
 * DMFramework
 * 
 * @license Copyright 2012 Dillen Meijboom under the Apache license version 2.0 (http://apache.org/licenses/LICENSE-2.0)
 * @author Dillen Meijboom <info@dillenm.nl>
 * @url http://dmframework.nl
 */

/**
 * The HTML class can be used to "clean" HTML output and some other functions.
 * 
 * @license Copyright 2012 Dillen Meijboom under the Apache license version 2.0 (http://apache.org/licenses/LICENSE-2.0)
 * @author Dillen Meijboom <info@dillenm.nl>
 * @package System.Library
 */
class Dmf_Html
{
    /**
     * Does this element have a XHTML ending? Like: <input />?
     * 
     * @param string $name
     * @return bool
     */
    public function isOneLiner( $name )
    {
        $elements = array( 'input', 'br', 'hr', 'label', 'link', 'td', 'th' );
        
        return in_array( $name, $elements );
    }
    
    /**
     * Create element object from element-string
     * 
     * @param string $string
     * @param Dmf_Stdclass $obj
     * @return Dmf_Stdclass 
     */
    public function getElement( $string )
    {
        preg_match( '/<([^ |>]*)([^>]*)/', $string, $match );
        
        $obj = new Dmf_Stdclass;
        
        if ( isset( $match['1'] ) )
        {
            $obj->tagname = $match['1'];
        }
        
        if ( isset( $match['2'] ) )
        {
            $attrs = explode( ' ', $match['2'] );
            
            foreach( $attrs as $attr )
            {
                preg_match( '/([^\=]*)=(.*)/', $attr, $attrInfo );
                
                if ( ! isset( $attrInfo['1'] ) ) continue;
                if ( ! isset( $attrInfo['2'] ) ) 
                {
                    $obj->$attrInfo['1'] = null;
                    continue;
                }
                
                if ( substr( $attrInfo['2'], 0, 1 ) == '"' || substr( $attrInfo['2'], 0, 1 ) == '\'' ) $attrInfo['2'] = substr( $attrInfo['2'], 1 );
                if ( substr( $attrInfo['2'], -1, strlen( $attrInfo['2'] ) ) == '"' || substr( $attrInfo['2'], -1, strlen( $attrInfo['2'] ) ) == '\'' ) $attrInfo['2'] = substr( $attrInfo['2'], 0, -1 );
                
                $obj->$attrInfo['1'] = $attrInfo['2'];
            }
        }
        
        $obj->render = function( $obj ) {
            $text = '<' . $obj->tagname . ' ';
            
            foreach( $obj as $key => $val )
            {
                if ( gettype( $val ) == 'string' && $key != 'tagname' )
                {
                    $text .= $key . '="' . $val . '" ';
                }
            }
            
            return $text . '/>';
        };
        
        return $obj;
    }
    
    /**
     * Cleanup messy HTML-code
     * 
     * @param string $html
     * @return string 
     */
    public function cleanup( $html )
    {
        $elements = array( 'fieldset', 'ol', 'li', 'select', 'button', 'form' );
        
        foreach( $elements as $element )
        {
            $html = preg_replace( '/<' . $element . '([^>]*)>/', '<' . $element . '$1>' . "\n", $html );
            $html = preg_replace( '/<\/' . $element . '>/', "\n" . '</' . $element . '>', $html );
        }
        
        $lines = explode( "\n", preg_replace( '/<\/([^>]*)>/', '</$1>' . "\n", $html ) );
        
        unset( $element );
        
        foreach( $lines as &$line )
        {
            if ( ! preg_match( '/[a-zA-Z0-9!\@\#\$\%\^\&\*\(\)\=\+]/', $line ) )
            {
                $line = null;
            }
        }
        
        $lines = array_values( array_filter( $lines ) );
        $result = '';
        $tab = 0;
        $elements = array();
        
        foreach( $lines as $line )
        {
            preg_match( '/<([^>]*)[ |>]/', $line, $element );
            
            //Calculate element
            if ( isset( $element['1'] ) )
            {
                list( $element ) = explode( ' ', $element['1'] );
            }
            else
            {
                $element = null;
            }
            
            //If the element has no tab-size and it's not a ending tag or a one-liner set element tab-size
            if ( ! isset( $elements[ $element ] ) && $element['0'] != '/' && ! $this->isOneLiner( $element ) )
            {
                $elements[ $element ] = $tab;
            }
            
            //If the element is a ending-tag remove the: "/"
            if ( $element['0'] == '/' )
            {
                $elements[ $element ] = isset( $elements[ substr( $element, 1 ) ] ) ? $elements[ substr( $element, 1 ) ] : $tab;
            }
            
            //Set tab-size to element tab-size if there is a element tab-size
            if ( isset( $elements[ $element ] ) ) $tab = $elements[ $element ];
            
            //Append result
            $result .= str_repeat( '    ', $tab ) . $line . PHP_EOL;
            
            //If element is a ending tag remove tab-size value
            if ( isset( $elements[ substr( $element, 1 ) ] ) && $element['0'] == '/' )
            {
                unset( $elements[ substr( $element, 1 ) ] );
                continue;
            }
            
            //If it needs a new-line
            if ( ! $this->isOneLiner( $element ) )
            {
                ++$tab;
            }
        }
        
        return PHP_EOL . $result . PHP_EOL;
    }
}